package cn.lzj.ymcc.service.impl;

import cn.lzj.ymcc.constants.RedisConstants;
import cn.lzj.ymcc.domain.MessageShielding;
import cn.lzj.ymcc.domain.MessageSms;
import cn.lzj.ymcc.dto.SmsCode2RedisDto;
import cn.lzj.ymcc.dto.SmsCodeDto;
import cn.lzj.ymcc.enums.CommonEorrorCode;
import cn.lzj.ymcc.exception.GlobleException;
import cn.lzj.ymcc.result.JSONResult;
import cn.lzj.ymcc.service.IMessageShieldingService;
import cn.lzj.ymcc.service.IMessageSmsService;
import cn.lzj.ymcc.service.ISmsCodeService;
import cn.lzj.ymcc.util.StrUtils;
import cn.lzj.ymcc.util.VerifyCodeUtils;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 *
 * 短信验证码发送流程
 *  1.刚需：参数校验   ，并且校验图片验证码
 *  2.获取上一次的图片验证码
 *
 *
 */
@Service
@Slf4j
public class SmsCodeServiceImpl implements ISmsCodeService {

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;
    @Autowired
    private IMessageSmsService messageSmsService ;
    @Autowired
    private IMessageShieldingService messageShieldingService;

    @Override
    public String imageCode(String imageCodeKey) {
        if(imageCodeKey.isEmpty()){
            throw new GlobleException("不能为空！！");
        }
        String code = StrUtils.getComplexRandomString(4);
        //4.生成验证码图片
        redisTemplate.opsForValue().set(imageCodeKey, code, 4, TimeUnit.MINUTES);
        //5.验证码图片转换为string
        //6.返回数据
        return VerifyCodeUtils.verifyCode(115, 42, code);
    }
    @Override
    public void sendSmsCode(SmsCodeDto smsCodeDto){
        nextsendSmsCode(smsCodeDto);
    }
    public void nextsendSmsCode(SmsCodeDto smsCodeDto) {
        //1.参数校验---断言已经帮我们做了
        //2.使用redis存储验证码，-- 存储验证码发送信息到数据库
        //3.
        //生成随机手机验证码的code
        //判断图形验证码是否正确，不正确就不让发送验证码
        Object redisCodeKeys = redisTemplate.opsForValue().get(smsCodeDto.getImageCodeKey());
        if(!redisCodeKeys.toString().equalsIgnoreCase(smsCodeDto.getImageCode())){
            throw new GlobleException("图形验证码错误！！");
        }
        //图形验证码正确后的逻辑
        /**
         *  ===============================================
         *   拉黑的逻辑
         *    1.后台会对拉黑的数据进行操作
         *    2.当点击发送验证码的时候，获取输入的手机号，获取当前操作的ip地址
         *    3.在拉黑的数据库中进行查询
         *    4.如果输入的手机号码或者ip地址一样
         *    5.报错并反馈给前台说这个手机号码或ip已经被拉黑，请联系管理员
         *    6.把拉黑的对象信息存入redsi缓存,后台对其进行操作时要重置redis
         *  ===============================================
         */
        String mobileMessage = smsCodeDto.getMobile();
        //1.去redis加载数据,有拉黑的数据就返回
        redisTemplate.opsForValue().get(mobileMessage);
        for (MessageShielding shielding : messageShieldingService.selectList(null)) {
            String shieldingPhone = shielding.getPhone();
            //拿到发送验证码手机的ip地址
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
            String remoteAddr = requestAttributes.getRequest().getRemoteAddr();
            //String shieldingIp1 = shielding.getIp();
            if(shieldingPhone.equals(mobileMessage)) { throw new GlobleException("您的手机号码或ip已经被拉黑！！请联系管理员"); }
            String shieldingIp = shielding.getIp();

            if(shieldingIp!=null&&shieldingIp==""){
                if(shieldingIp.equals(remoteAddr)){ throw new GlobleException("您的手机号码或ip已经被拉黑！！请联系管理员"); }
            }
        }
        Date NowTime = new Date();
        //把验证码存储到redis，设置过期时间

        String smskey = String.format(RedisConstants.KEY_SMS_CODE_PREFIX, smsCodeDto.getMobile());

        //smskey  前缀加上手机号码
        //String smskey ="SendMessage:" + smsCodeDto.getMobile();
        //获取上次发送的验证码，和时间戳
        SmsCode2RedisDto lastSendCode  = (SmsCode2RedisDto)redisTemplate.opsForValue().get(smskey);
        //要发送的手机验证码
        String code=null;
        if(lastSendCode!=null){
            Long sendcodetime = lastSendCode.getSendcodetime();
            //判断时间差是否大于60秒
            if((NowTime.getTime()-sendcodetime)/1000<60){
                //小于60秒，抛出异常
                throw new GlobleException("操作过于频繁，请稍后再试！！");
            }
            //大于60秒，发送之前的验证码
              code = lastSendCode.getCode();
        }else {
            //超过十分钟，重新发送新的验证码
            code = StrUtils.getComplexRandomString(6);
        }

        redisTemplate.opsForValue().set(smskey, new SmsCode2RedisDto(code,NowTime.getTime()),10,TimeUnit.MINUTES);
        //校验手机号码是否已经被注册
        String context="尊敬的用户，您的验证码为"+code+"请在十分钟之内使用！！";
        log.info(context);
        //把发送手机验证码日志的信息记录到日志表里面
        MessageSms messageSms = new MessageSms();
        messageSms.setTitle("Send verification code");
        messageSms.setContent(context);
        //获取上下文路径，，获取ip地址
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        String remoteAddr = requestAttributes.getRequest().getRemoteAddr();
        messageSms.setIp(remoteAddr);
        messageSms.setPhone(smsCodeDto.getMobile());
        messageSms.setSendTime(NowTime);
        messageSmsService.insert(messageSms);
    }

}
